
package com.trydofor.id.loader;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import com.trydofor.aloe.exception.Exceptions;
import com.trydofor.id.core.A9Loader;

/**
 * @author : Shi Rongjiu (www.trydofor.com)
 */
public final class PureJdbcEntry extends PureJdbcLoader implements A9Loader<List<Long>> {
    
    private static final String SLT_VALUE;
    private static final String UPD_VALUE;
    
    // init final
    static {
        SLT_VALUE = "SELECT LONG_VALUE FROM LONG_ENTRY WHERE LONG_MAKER=? AND LONG_USEBY=0";
        UPD_VALUE = "UPDATE LONG_ENTRY SET LONG_USEBY=? WHERE LONG_MAKER=? AND LONG_VALUE=? AND LONG_USEBY=0";
    }
    
    /**
     * {@inheritDoc}
     */
    public PureJdbcEntry(String mk, DataSource ds, int id) throws SQLException {
        super(mk, ds, id);
    }
    
    /**
     * {@inheritDoc}
     */
    public PureJdbcEntry(int mk, DataSource ds, int id) {
        super(mk, ds, id);
    }
    
    @Override
    public List<Long> heavyLoad() throws Exception {
        List<Long> result = new ArrayList<Long>(fetchCount);
        
        final Connection conn = dataSource.getConnection();
        final boolean autoCommit = conn.getAutoCommit();
        PreparedStatement pst = null;
        Savepoint savepoint = null;
        try {
            // select
            pst = conn.prepareStatement(SLT_VALUE);
            pst.setFetchSize(fetchCount); // depends on the impls
            pst.setMaxRows(fetchCount); // depends on the impls
            pst.setInt(1, makerId);
            ResultSet rs = pst.executeQuery();
            while (rs.next()) {
                long st = rs.getLong(1);
                result.add(Long.valueOf(st));
            }
            rs.close();
            pst.close();
            
            // update
            if (result.size() > 0) {
                if (autoCommit) {
                    conn.setAutoCommit(false);
                }
                savepoint = conn.setSavepoint();
                pst = conn.prepareStatement(UPD_VALUE);
                for (Long long1 : result) {
                    pst.setInt(1, loaderId);
                    pst.setInt(2, makerId);
                    pst.setLong(3, long1.longValue());
                    pst.addBatch();
                }
                
                int[] rc = pst.executeBatch();
                for (int i = 0; i < rc.length; i++) {
                    if (rc[i] != 1) {
                        throw new SQLException("rollback for " + rc[i] + " records updated. maker=" + makerId);
                    }
                }
                conn.commit();
            }
        }
        catch (Exception e) {
            if (savepoint != null) {
                conn.rollback(savepoint);
            }
            throw e;
        }
        finally {
            if (autoCommit) {
                conn.setAutoCommit(true);
            }
            if (pst != null) {
                pst.close();
            }
        }
        return result;
    }
    
    @Override
    public void handleException(Exception e) {
        Exceptions.throwFakeException(e);
    }
}
